package containerlogistik.implementation;

import containerlogistik.interfaces.*;

public class TrackSectionImpl implements TrackSection {

    public static final TrackSection DEFAULT_TRACK = new TrackSectionImpl("DefaultTrack", Values.ZERO_POINT, Values.ZERO_POINT, Values.ZERO_ANGLE, Values.levelOfPedal(1), Values.ZERO_LENGTH, true);
    
    private final String name;
    private final Point startPoint;
    private final Point endPoint;
    private final Point radiusPoint;
    private final Angle angle;
    private final Length radius;
    private final Length length;
    private final Level traction;
    private final Length sumLength;
    private final boolean isLeftCurve;

    public TrackSectionImpl(String name, Point startPoint, Point endPoint, Angle angle, Level traction, Length prevLength, boolean isLeftCurve) {
        this.name = name;
        this.startPoint = startPoint;
        this.endPoint = endPoint;
        this.angle = angle;
        this.traction = traction;
        this.isLeftCurve = isLeftCurve;

        final Point pointDiff = startPoint.sub(endPoint);
        Length distanceStartEnd = Values.lengthInM(Math.sqrt(Math.pow(pointDiff.x(), 2) + Math.pow(pointDiff.y(), 2)));

        if (angle.isZero()) {
            this.radius = Values.lengthInM(0.0);
            this.length = distanceStartEnd;
            this.sumLength = this.length.add(prevLength);
            this.radiusPoint = startPoint;
        } else {
            double angleDistanceRadius = (180 - angle.deg()) / 2;

            this.radius = Values.lengthInM((distanceStartEnd.m() * Math.sin(Math.toRadians(angleDistanceRadius))) / Math.sin(this.angle.rad()));
            this.length = Values.lengthInM((((this.radius.m() * 2 * Math.PI) / 360) * this.angle.deg()));
            this.sumLength = this.length.add(prevLength);

            boolean isXPositive = (startPoint.x() <= endPoint.x());
            boolean isYPositive = (startPoint.y() <= endPoint.y());

            if (isLeftCurve) {
                if (isXPositive && isYPositive) {
                    this.radiusPoint = startPoint.addOnX(this.radius.m());
                } else if (isXPositive && !isYPositive) {
                    this.radiusPoint = startPoint.subOnY(this.radius.m());
                } else if (!isXPositive && !isYPositive) {
                    this.radiusPoint = startPoint.subOnX(this.radius.m());
                } else if (!isXPositive && isYPositive) {
                    this.radiusPoint = startPoint.addOnY(this.radius.m());
                } else {
                    this.radiusPoint = Values.ZERO_POINT;
                }
            } else {
                if (isXPositive && isYPositive) {
                    this.radiusPoint = startPoint.addOnY(this.radius.m());
                } else if (isXPositive && !isYPositive) {
                    this.radiusPoint = startPoint.addOnX(this.radius.m());
                } else if (!isXPositive && !isYPositive) {
                    this.radiusPoint = startPoint.subOnY(this.radius.m());
                } else if (!isXPositive && isYPositive) {
                    this.radiusPoint = startPoint.subOnX(this.radius.m());
                } else {
                    this.radiusPoint = Values.ZERO_POINT;
                }
            }
        }
    }

    public String name() {
        return this.name;
    }

    public Point startPoint() {
        return this.startPoint;
    }

    public Point endPoint() {
        return this.endPoint;
    }

    public Angle angle() {
        return this.angle;
    }

    public Length radius() {
        return this.radius;
    }

    public Length length() {
        return this.length;
    }

    public Level traction() {
        return this.traction;
    }

    public Length sumLength() {
        return this.sumLength;
    }

    public Point radiusPoint() {
        return this.radiusPoint;
    }
}
